﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using COFE.Core.Lister;
using COFE.Core.Utils;
using System.Net;
using COFE.Core;
using System.IO;
using COFE.Web;
using System.Security;
using System.Xml.Linq;

namespace COFE.IO.COFEWS
{
    public class COFEWSDirectoryLister : PrimaryDirectoryListerBase<Entry>
    {
        #region Constructor

        static string uriLogin = "{0}/users/signin";
        static string strUserAndPass = "username={0}&password={1}";
        static string uriLookupEntry = "{0}/lookup?path={1}";
        //static string uriListPath = "{0}/lookup?path={1}&rel=list";

        public COFEWSDirectoryLister(IFactory<IDirectoryLister> factory,
            string listerKey, string rootUri = @"http://localhost:62863",
            string userName = "Test", string password = "Test")
            : base(factory, listerKey)
        {
            _rootUri = rootUri.TrimEnd('/');
            _userName = userName;
            _password = password;

            
            Login();

            _parse = (path) => this.getEntry(path);
            _list = (parentEntry) =>
                this.list(parentEntry).Entries;
            _getParent = (entry) =>
                {
                    if (entry.Path == "")
                        return null;

                    string parentPath =
                        COFEWSPath.FromCOFEPath(
                        COFEPath.GetDirectoryName(entry.Path)
                        );

                    return this.getEntry(parentPath);

                };
            _getRootDirectory = () =>  _list(_parse("")).ToArray();
        }

        #endregion

        #region Methods


        public T SendRequest<T>(string uri, string method,
            Func<WebResponse, T> handlerResponseFunc)
        {           

            try
            {
                return
                    handlerResponseFunc(
                    COFEWSShared.NetClient.SendRequest(uri, method, null));
            }
            catch (WebException ex)
            {
                if (ex.Message.IndexOf("401") != -1)
                {
                    Login();
                    return handlerResponseFunc(
                    COFEWSShared.NetClient.SendRequest(uri, method, null));
                }
                else throw ex;
            }
        }

        public void Login()
        {
            try
            {
                Status = DirectoryListerStatusMode.Offline;

                string uri = String.Format(uriLogin, _rootUri);

                MemoryStream ms = new MemoryStream();
                var sw = new StreamWriter(ms);
                sw.Write(String.Format(strUserAndPass, _userName, _password));
                sw.Flush();
                ms.Seek(0, SeekOrigin.Begin);

                var response = COFEWSShared.NetClient.SendRequest(uri, "POST", ms);

                Status = DirectoryListerStatusMode.Online;
            }
            catch (Exception ex)
            {

                throw new SecurityException("Login failed.");
            }
            //Console.WriteLine(response.StatusCode);
        }

        //public EntryList list(string path)
        //{
        //    string uri = String.Format(uriListPath, _rootUri, path);

        //    return SendRequest(uri, "GET", (response) =>
        //        {
        //            return XmlStreamUtils.EntryListFromXmlStream(_rootUri,
        //                response.GetResponseStream()
        //                );
        //        });
        //}

        public EntryList list(Entry parentEntry)
        {
            var listLink = parentEntry.Links.FirstOrDefault((l) => l.Relation == RelationType.List);
            if (listLink == null)
                throw new NotSupportedException(parentEntry.Name + " do not support list.");
            string uri = _rootUri + listLink.Uri;

            return SendRequest(uri, "GET", (response) =>
            {
                return XmlStreamUtils.EntryListFromXmlStream(_rootUri,
                    response.GetResponseStream()
                    );
            });
        }

        public Entry getEntry(string path)
        {
            string fullPath = COFEPath.FormatFullParseName(ListerKey, path);
            if (!_cachedEntry.ContainsKey(fullPath))
            {

                string uri = String.Format(uriLookupEntry, _rootUri, path);

                _cachedEntry.Add(fullPath, SendRequest(uri, "GET", (response) =>
                {
                    XElement outerXml = XElement.Load(new StreamReader(response.GetResponseStream()));
                    return Entry.FromXElement(_rootUri, outerXml);
                }));
            }
            return _cachedEntry[fullPath];
        }

        public override IStreamProvider CreateStreamProvider()
        {
            return new COFEWSStreamProvider(this);
        }

        public override IDirectoryController CreateController()
        {
            return new COFEWSDirectoryController(this);
        }

        public override IPropertyProvider CreatePropertyProvider(Entry item)
        {
            return new COFEWSPropertyProvider(this, item);
        }

        #endregion

        #region Data

        internal string _rootUri, _userName, _password;
        private static CookieContainer cookies = new CookieContainer();
        private static Dictionary<string, Entry> _cachedEntry
            = new Dictionary<string, Entry>();

        #endregion

        #region Public Properties

        #endregion

    }
}
